package org.darkforest.controller;

import org.darkforest.common.logger.Logger;
import org.darkforest.common.util.AliOssFileUploadUtil;
import org.darkforest.common.util.DateUtil;
import org.darkforest.common.util.PicCompressUtil;
import org.darkforest.enums.AjaxMsgTypeEnum;
import org.darkforest.model.AlbumPic;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * Created by valentina on 15/2/19.
 * 1、继承时需要赋值子类的泛型声明！！！给logger使用否则会抛异常
 * 2、上传图片的临时压缩目录路径默认为webapp/temp，如有该目录tempPath可赋值null，否则请传值
 * 3、albumId可为空，空值时上传到根目录
 * 4、压缩图片尺寸根据实际情况传值,也可自行添加静态变量使用
 * 5、上传图片是否成功可从AlbumPic.uploadState字段取值判断,上传之后的图片名从AlbumPic.apicCover取值，图片原名从AlbumPic.apicName取值
 */
public abstract class WebController<T>{

    @SuppressWarnings("unchecked")
    private Class cls = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

    protected final org.slf4j.Logger LOGGER = Logger.getLogger(cls);

    public static final String[] goodsPicSize = {"360", "240", "60"};        // 图片压缩尺寸从配置文件中读取

    public static final String[] goodsCommentPicSize = {"120"};              // 商品评论图片压缩尺寸

    protected static final String PIC_TEMP_PATH = "temp";                    // 图片上传临时目录,避免写死尽量配置为变量

    /**
     * 上传图片并返回图片信息对象列表
     *
     * @param request      必填
     * @param compressSize 必填
     * @param tempPath     可为空
     * @param albumId      可为空
     * @return
     */
    protected LinkedList<AlbumPic> uploadPics(MultipartHttpServletRequest request, String[] compressSize, String tempPath, String albumId) {
        String tempDir = tempPath == null ? (request.getSession().getServletContext().getRealPath(PIC_TEMP_PATH) + "/") : tempPath;
        String[] picSize = compressSize == null ? goodsPicSize : compressSize;          //默认为商品图片压缩尺寸
        LinkedList<AlbumPic> picList = new LinkedList<AlbumPic>();
        AlbumPic pic;
        //1.获取上传文件名集合
        Iterator<String> itr = request.getFileNames();
        MultipartFile mpf = null;

        //2.循环处理文件:获取文件
        while (itr.hasNext()) {

            //2.1 获取文件对象
            mpf = request.getFile(itr.next());
            LOGGER.debug("" + mpf.getOriginalFilename() + " uploaded! ");

            //2.2 检验文件类型，文件大小，如不符合条件则返回 TODO
//            if()


            //2.3 创建图片对象
            String pic_suffix = mpf.getOriginalFilename().substring(mpf.getOriginalFilename().lastIndexOf("."));        //文件后缀
            String picName = AliOssFileUploadUtil.getPicNewName() + pic_suffix;                                           //重命名后的文件名
            String pic_originalName = mpf.getOriginalFilename().replace(pic_suffix, "");                                 //去除后缀的原文件名
            pic = new AlbumPic();

            try {
                pic.setBytes(mpf.getBytes());

                // 复制文件到项目temp目录下，进行压缩处理
                FileCopyUtils.copy(mpf.getBytes(), new FileOutputStream(tempDir + picName));
                File uploadFile = new File(tempDir + picName);

                //压缩4个尺寸缩略图：1280 360 240 60，并上传
                PicCompressUtil compressUtil = new PicCompressUtil();
//                String[] size = compressPicSize.split(",");
                compressUtil.compressPic(tempDir, picName, picSize);
                //上传到云空间
                AliOssFileUploadUtil.uploadPic(albumId, picName, uploadFile);
                for (String i : picSize) {
                    AliOssFileUploadUtil.uploadPic(albumId, i + "_" + picName, new File(tempDir+i+"_"+picName));
                }
                //保存图片数据到数据库
                pic.setApicName(pic_originalName);
                pic.setApicSuffix(pic_suffix);
                pic.setApicSize((int) mpf.getSize() / 1024);
                pic.setUploadTime(DateUtil.unixTimeStamp());

                pic.setApicSpec(PicCompressUtil.getPicWH(tempDir + picName));
                pic.setApicTag("");
                pic.setApicCover(picName);

                //删除temp下的临时文件
                File o_pic = new File(tempDir + picName);
                if (o_pic.exists()) {     //删除原图
                    LOGGER.debug("删除：" + o_pic.getName());
                    o_pic.delete();
                }
                for (String i : picSize) {
                    File del_pic = new File(tempDir + i + "_" + picName);
                    if (del_pic.exists()) {  //删除缩略图
                        LOGGER.debug("删除：" + del_pic.getName());
                        del_pic.delete();
                    }
                }
                //设置上传成功,返回页面ajax操作使用
                pic.setUploadState(true);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                pic.setUploadState(false);      //异常时设置状态为失败
                e.printStackTrace();
            } finally {
                //2.4 清空二进制流数据后 添加到返回对象
                pic.setBytes(null);
                picList.add(pic);
            }
        }
        return picList;
    }


    /**
     * 获取ajax请求返回报文，xml格式
     *
     * @param msg     返回消息内容
     * @param msgType 消息类型
     * @param url     返回后跳转url
     * @param time    对话框持续时间(s)
     */
    public String getDialogXMLTemplete(String msg, AjaxMsgTypeEnum msgType, String url, int time) {
        return "<![CDATA[" +msg + "<script type=\"text/javascript\" reload=\"1\">showDialog('" + msg + "', '" + msgType.getText() + "'," +
                " null, function (){window.location.href ='" + url + "'}, 0, null, null, null, null, " + time + ", null);</script><script type=\"text/javascript\" reload=\"1\">CUR_DIALOG.close();</script>]]>";
    }

    public String getDialogJsTemplete(String msg, AjaxMsgTypeEnum msgType, String url, int time) {
        return "<script type=\"text/javascript\" src=\"/resources/js/jquery.js\"></script>" +
                "<script type=\"text/javascript\" src=\"/resources/js/dialog/dialog.js\" id=\"dialog_js\" charset=\"utf-8\"></script>" +
                "<script type=\"text/javascript\" reload=\"1\">showDialog('" + msg + "', '" + msgType.getText() + "'," +
                " null, function (){window.location.href ='" + url + "'}, 0, null, null, null, null, " + time + ", null);</script>";
    }


    public String cut(String picPath, int x, int y, int width, int height, String temp) throws IOException {
        //FileInputStream is = null;  
        ImageInputStream iis = null;
        try {
            URL realUrl = new URL(picPath);
            // 打开和URL之间的连接
            URLConnection con = realUrl.openConnection();
            con.connect();
            // 读取图片文件  
            //is = (FileInputStream)mpf.getInputStream();  
            /* 
             * 返回包含所有当前已注册 ImageReader 的 Iterator，这些 ImageReader 声称能够解码指定格式。 
             * 参数：formatName - 包含非正式格式名称 . （例如 "jpeg" 或 "tiff"）等 。 
             */
            Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = it.next();
            // 获取图片流  
            iis = ImageIO.createImageInputStream(con.getInputStream());  
            /* 
             * <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。 
             * 此设置意味着包含在输入源中的图像将只按顺序读取，可能允许 reader 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。 
             */
            reader.setInput(iis, true);  
            /* 
             * <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O 
             * 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件 将从其 ImageReader 实现的 
             * getDefaultReadParam 方法中返回 ImageReadParam 的实例。 
             */
            ImageReadParam param = reader.getDefaultReadParam();  
            /* 
             * 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域，通过 Rectangle 对象 
             * 的左上顶点的坐标（x，y）、宽度和高度可以定义这个区域。 
             */
            Rectangle rect = new Rectangle(x, y, width, height);
            // 提供一个 BufferedImage，将其用作解码像素数据的目标。  
            param.setSourceRegion(rect);  
            /* 
             * 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象，并将 它作为一个完整的 
             * BufferedImage 返回。 
             */
            BufferedImage bi = reader.read(0, param);
            String pic_suffix = picPath.substring(picPath.lastIndexOf("."));        //文件后缀
            String picName = AliOssFileUploadUtil.getPicNewName() + pic_suffix;
            ImageIO.write(bi, "jpg", new File(temp + picName));
            File uploadFile = new File(temp + picName);

            //压缩4个尺寸缩略图：1280 360 240 60，并上传
            PicCompressUtil compressUtil = new PicCompressUtil();
//            String[] size = compressPicSize.split(",");
            compressUtil.compressPic(temp, picName, goodsPicSize);
            //上传到云空间
            AliOssFileUploadUtil.uploadPic("", picName, uploadFile);
            for (String i : goodsPicSize) {
                AliOssFileUploadUtil.uploadPic("", i + "_" + picName, uploadFile);
            }
            //删除temp下的临时文件
            File o_pic = new File(temp + picName);
            if (o_pic.exists()) {     //删除原图
                LOGGER.debug("删除：" + o_pic.getName());
                o_pic.delete();
            }
            for (String i : goodsPicSize) {
                File del_pic = new File(temp + i + "_" + picName);
                if (del_pic.exists()) {  //删除缩略图
                    LOGGER.debug("删除：" + del_pic.getName());
                    del_pic.delete();
                }
            }
            return picName;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (iis != null)
                iis.close();
        }
        return "";

    }


    protected String uploadPicsWithoutCompressSize(MultipartFile mpf,MultipartHttpServletRequest request, String tempPath, String albumId) {
        String tempDir = tempPath == null ? (request.getSession().getServletContext().getRealPath(PIC_TEMP_PATH) + "/") : tempPath;
        LinkedList<AlbumPic> picList = new LinkedList<AlbumPic>();
        AlbumPic pic;
            LOGGER.debug("" + mpf.getOriginalFilename() + " uploaded! ");
            String pic_suffix = mpf.getOriginalFilename().substring(mpf.getOriginalFilename().lastIndexOf("."));        //文件后缀
            String picName = AliOssFileUploadUtil.getPicNewName() + pic_suffix;                                           //重命名后的文件名
            String pic_originalName = mpf.getOriginalFilename().replace(pic_suffix, "");                                 //去除后缀的原文件名
            pic = new AlbumPic();

            try {
                pic.setBytes(mpf.getBytes());

                // 复制文件到项目temp目录下，进行压缩处理
                FileCopyUtils.copy(mpf.getBytes(), new FileOutputStream(tempDir + picName));
                File uploadFile = new File(tempDir + picName);

                //压缩4个尺寸缩略图：1280 360 240 60，并上传
                PicCompressUtil compressUtil = new PicCompressUtil();
//                String[] size = compressPicSize.split(",");
                //上传到云空间
                AliOssFileUploadUtil.uploadPic(albumId, picName, uploadFile);

                //保存图片数据到数据库
                pic.setApicName(pic_originalName);
                pic.setApicSuffix(pic_suffix);
                pic.setApicSize((int) mpf.getSize() / 1024);
                pic.setUploadTime(DateUtil.unixTimeStamp());

                pic.setApicSpec(PicCompressUtil.getPicWH(tempDir + picName));
                pic.setApicTag("");
                pic.setApicCover(picName);


                //删除temp下的临时文件
                File o_pic = new File(tempDir + picName);
                if (o_pic.exists()) {     //删除原图
                    LOGGER.debug("删除：" + o_pic.getName());
                    o_pic.delete();
                }

                //设置上传成功,返回页面ajax操作使用
                pic.setUploadState(true);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                pic.setUploadState(false);      //异常时设置状态为失败
                e.printStackTrace();
            } finally {
                //2.4 清空二进制流数据后 添加到返回对象
                pic.setBytes(null);
                picList.add(pic);
            }

        return picName;
    }
}
